﻿using System;
using System.Collections.Generic;
using Internal.Runtime.Services.Battle.StateMachine;
using Runtime.Services.Battle;
using Runtime.Services.Battle.StateMachine;
using UnityEngine;
using UnityEngine.Pool;

namespace Runtime.Services.Battle.StateMachine {

    /// <summary>
    /// 指定一对<see cref="UnityEngine.GameObject"/>进行显示的状态机
    /// </summary>
    public interface IDFR_BattleEntityStateMachine_OverlapGameObject : IDFR_BattleEntityStateMachine {

        /// <summary>
        /// 显示状态提供者
        /// </summary>
        public interface IStateProvider {

            public const int INDEX_IDLE = 0;

            public const int INDEX_OVER = 1;

            /// <summary>
            /// 闲置
            /// </summary>
            GameObject Idle { get; }

            /// <summary>
            /// 非闲置
            /// </summary>
            GameObject Over { get; }
        }
    }

    [Implement(typeof(IDFR_BattleEntityStateMachine_OverlapGameObject))]
    internal sealed class DFR_BattleEntityStateMachine_OverlapGameObject : DFR_BattleEntityStateMachine, IDFR_BattleEntityStateMachine_OverlapGameObject, IDFR_BattleEntityStateMachineInternal_OverlapGameObject {

        private IDFR_BattleEntityAssetVehicle<IDFR_BattleEntityStateMachine_OverlapGameObject.IStateProvider> m_StateVehicle;

        private GameObject m_IdleGameObject;
        private Dictionary<DFR_BattleEntityState, GameObject> m_StateGameObjectDictionary;

        private DFR_BattleEntityState m_LastState;

        private bool m_ForceRefreshState;
        public bool IsStateChanged => State != m_LastState || m_ForceRefreshState;

        public override bool IsInitialized => m_IdleGameObject != null && m_StateGameObjectDictionary != null;

        private IParticleReferences m_IdleParticleReferences;
        private Dictionary<DFR_BattleEntityState, IParticleReferences> m_StateParticleReferencesDictionary;

        private float m_PlaySpeed;

        void IDFR_BattleEntityStateMachineInternal_OverlapGameObject.Initialize(IDFR_BattleEntityAssetVehicle<IDFR_BattleEntityStateMachine_OverlapGameObject.IStateProvider> stateVehicle) {
            UnityEngine.Assertions.Assert.IsNotNull(stateVehicle);

            m_StateVehicle = stateVehicle;
            m_StateVehicle.Loaded += OnStateVehicleLoaded;
            OnStateVehicleLoaded();
        }

        protected override void Allocate() {
            base.Allocate();
            m_PlaySpeed = 0f;
            m_LastState = State = DFR_BattleEntityState.Unknown;
            m_ForceRefreshState = false;
        }

        protected override void Release() {
            if (ReleaseParticle(m_IdleParticleReferences)) {
                m_IdleParticleReferences = null;
            }
            if (m_StateParticleReferencesDictionary != null) {
                foreach (var kv in m_StateParticleReferencesDictionary) {
                    var particleReferences = kv.Value;
                    ReleaseParticle(particleReferences);
                }
                DictionaryPool<DFR_BattleEntityState, IParticleReferences>.Release(m_StateParticleReferencesDictionary);
                m_StateParticleReferencesDictionary = null;
            }

            m_IdleGameObject = null;
            if (m_StateGameObjectDictionary != null) {
                DictionaryPool<DFR_BattleEntityState, GameObject>.Release(m_StateGameObjectDictionary);
                m_StateGameObjectDictionary = null;
            }

            m_StateVehicle = null;
        }

        private void OnStateVehicleLoaded() {
            if (m_StateVehicle.Content == null) {
                return;
            }

            m_IdleGameObject = m_StateVehicle.Content.Idle;
            m_IdleGameObject.SetActive(m_LastState != DFR_BattleEntityState.Unknown);
            m_StateGameObjectDictionary = DictionaryPool<DFR_BattleEntityState, GameObject>.Get();
            m_StateGameObjectDictionary[DFR_BattleEntityState.Attack] = m_StateVehicle.Content.Over;
            foreach (var kv in m_StateGameObjectDictionary) {
                kv.Value.SetActive(false);
            }

            m_StateParticleReferencesDictionary = DictionaryPool<DFR_BattleEntityState, IParticleReferences>.Get();

            m_ForceRefreshState = true;
            Play(m_PlaySpeed);
        }

        public override void Play(float speed) {
            m_PlaySpeed = speed;

            if (!IsInitialized) {
                return;
            }
            if (State == DFR_BattleEntityState.Unknown) {
                return;
            }

            bool isStateChanged = IsStateChanged || m_ForceRefreshState;
            m_ForceRefreshState = false;
            if (isStateChanged) {
                if (State != DFR_BattleEntityState.Idle) {
                    foreach (var kv in m_StateGameObjectDictionary) {
                        kv.Value.SetActive(kv.Key == State);
                    }
                }
                if (!m_IdleGameObject.activeSelf) {
                    m_IdleGameObject.SetActive(true);
                }
                m_LastState = State;
            }

            ProcessParticle(isStateChanged, speed, m_IdleGameObject, ref m_IdleParticleReferences);
            if (m_StateGameObjectDictionary.TryGetValue(State, out var stateGameObject)) {
                var isExist = m_StateParticleReferencesDictionary.TryGetValue(State, out var particleReferences);
                ProcessParticle(isStateChanged, speed, stateGameObject, ref particleReferences);
                if (!isExist) {
                    m_StateParticleReferencesDictionary.Add(State, particleReferences);
                }
            }
        }
    }
}

namespace Internal.Runtime.Services.Battle.StateMachine {

    public interface IDFR_BattleEntityStateMachineInternal_OverlapGameObject : IDFR_BattleEntityStateMachine, IDisposable {

        void Initialize(IDFR_BattleEntityAssetVehicle<IDFR_BattleEntityStateMachine_OverlapGameObject.IStateProvider> stateVehicle);
    }
}